# sources
gcc_components := binutils gcc gdb
gcc_components_sources := $(foreach compo, $(gcc_components), $(compo)/sources)
msp_components := msp430-libc msp430mcu mspdebug
msp_components_sources := $(foreach compo, $(msp_components), $(compo)/sources)
all_components := $(gcc_components) $(msp_components)
all_components_sources := $(gcc_components_sources) $(msp_components_sources)

# patchs
to_patch := mspgcc
to_patch_files := $(foreach one, $(to_patch), $(one)/.patched_sources)

# build dir and install dir
BUILD_DIR := _build_
INSTALL_DIR := $(shell pwd)/install

export PATH := $(INSTALL_DIR)/bin:$(PATH)
export LD_LIBRARY := $(INSTALL_DIR)/lib:$(LD_LIBRARY)

# 
GCC_TOOLCHAIN_TARGET := msp430
GCC_TOOLCHAIN_PROGRAM_PREFIX := msp430-

export BUILD_DIR INSTALL_DIR GCC_TOOLCHAIN_TARGET GCC_TOOLCHAIN_PROGRAM_PREFIX

install: $(all_components)
	@echo ========== all done ===============================
	@echo Toolchain installed into:
	@echo "    $(INSTALL_DIR)"
	@echo ===================================================

#================= MSP430 =====================================================
mspdebug: $(INSTALL_DIR)/bin/mspdebug
$(INSTALL_DIR)/bin/mspdebug: mspdebug/sources/mspdebug
	@($(MAKE) $(MFLAGS) -C mspdebug install)
mspdebug/sources/mspdebug: $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)gcc $(INSTALL_DIR)/msp430/lib/libc.a
	@($(MAKE) $(MFLAGS) -C mspdebug build)

msp430-libc: $(INSTALL_DIR)/msp430/lib/libc.a
$(INSTALL_DIR)/msp430/lib/libc.a: msp430-libc/sources/src/Build
	@($(MAKE) $(MFLAGS) -C msp430-libc install)
msp430-libc/sources/src/Build: $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)gcc $(INSTALL_DIR)/bin/msp430mcu-config
	@($(MAKE) $(MFLAGS) -C msp430-libc build)

msp430mcu: $(INSTALL_DIR)/bin/msp430mcu-config
$(INSTALL_DIR)/bin/msp430mcu-config: $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)ar $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)gcc $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)gdb
	@($(MAKE) $(MFLAGS) -C msp430mcu install)

#================= GCC TOOLCHAIN ==============================================
# gdb build and install
.PHONY:gdb
gdb: $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)gdb
$(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)gdb: gdb/$(BUILD_DIR)/gdb/gdb
	@($(MAKE) $(MFLAGS) -C gdb install)
gdb/$(BUILD_DIR)/gdb/gdb: $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)ar $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)gcc $(to_patch_files)
	@($(MAKE) $(MFLAGS) -C gdb build)

# gcc build and install
.PHONY:gcc
gcc: $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)gcc
$(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)gcc: gcc/$(BUILD_DIR)/$(GCC_TOOLCHAIN_TARGET)/libgcc/libgcc.a
	@($(MAKE) $(MFLAGS) -C gcc install)
gcc/$(BUILD_DIR)/$(GCC_TOOLCHAIN_TARGET)/libgcc/libgcc.a: $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)ar $(to_patch_files)
	@($(MAKE) $(MFLAGS) -C gcc build)

# binutils build and install
.PHONY:binutils
binutils: $(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)ar
$(INSTALL_DIR)/bin/$(GCC_TOOLCHAIN_PROGRAM_PREFIX)ar: binutils/$(BUILD_DIR)/binutils/ar
	@($(MAKE) $(MFLAGS) -C binutils install)
binutils/$(BUILD_DIR)/binutils/ar: $(to_patch_files)
	@($(MAKE) $(MFLAGS) -C binutils build)

#================= Preparations ===============================================
.PHONY:sources
sources: $(all_components_sources)
	@($(MAKE) $(MFLAGS) -C $(to_patch) init)
%/sources:
	@($(MAKE) $(MFLAGS) -C $(subst /sources,,$@) init)

.PHONY:patch
patch: $(to_patch_files)
%/.patched_sources: $(all_components_sources)
	@($(MAKE) $(MFLAGS) -C $(subst /.patched_sources,,$@) patch)

unpatch:
	@$(foreach dir, $(to_patch), $(MAKE) $(MFLAGS) -C $(dir) unpatch;)

.PHONY:uninstall
uninstall:
	$(RM) -r $(INSTALL_DIR)
	
.PHONY:clean
clean:
	@$(foreach compo, $(all_components) $(to_patch), $(MAKE) $(MFLAGS) -C $(compo) clean;)

.PHONY:distclean
distclean:
	@$(foreach compo, $(all_components) $(to_patch), $(MAKE) $(MFLAGS) -C $(compo) distclean;)

.PHONY:distdistclean
distdistclean:
	@$(foreach compo, $(all_components) $(to_patch), $(MAKE) $(MFLAGS) -C $(compo) distdistclean;)
